/**
 * CRC校验计算函数
 * @param data
 * @returns {number}
 */
function calculateCRC(data) {
    let crc = 0xFFFF; // 初始值
    for (let i = 0; i < data.length; i++) {
        crc ^= data[i];
        for (let j = 0; j < 8; j++) {
            if (crc & 0x0001) {
                crc = (crc >> 1) ^ 0xA001;
            } else {
                crc >>= 1;
            }
        }
    }
    return crc;
}

/**
 * 生成设置比特位的CRC校验的数据帧
 * @param slaveId 设备地址（从站ID）
 * @param functionCode  功能码
 * @param registerAddress 寄存器地址
 * @param registerValue  寄存器的值
 * @returns string
 */
function migrateCRCModbusFrameStr(slaveId, functionCode, registerAddress, registerValue) {
    // step1: 保存寄存器的值到本地存储中
    serialLocalStorage.put("registerAddress", registerAddress)

    // step2: 生成数据帧
    const modbusFrame = [
        slaveId, // 地址
        functionCode, // 功能码
        registerAddress >> 8, // 起始地址高位
        registerAddress & 0xFF, // 起始地址低位
        registerValue >> 8, // 寄存器数量高位
        registerValue & 0xFF, // 寄存器数量低位
    ];
    console.log("未生成CRC校验过的数据帧：" + modbusFrame)

    // step3: 计算CRC校验
    const crc = calculateCRC(modbusFrame);
    modbusFrame.push(crc & 0xFF); // CRC低位
    modbusFrame.push(crc >> 8); // CRC高位
    console.log("生成CRC校验过后的数据帧：" + modbusFrame)

    // step4: 数据帧转成字符串
    const modbusFrameStr = modbusFrame.map(byte => byte.toString(16).padStart(2, '0')).join('');
    console.log("生成CRC校验过后的数据帧字符串：" + modbusFrame)
    return modbusFrameStr
}


/**
 * 发送串口命令
 * @param slaveId 设备地址（从站ID）
 * @param functionCode  功能码（写单一保持寄存器）
 * @param registerAddress 寄存器地址
 * @param registerValue 寄存器值
 * @return boolean
 */
function sendSerialCommand(slaveId, functionCode, registerAddress, registerValue) {
    // step1: 组成校验的CRC数据帧字符串
    const modbusFrameStr = migrateCRCModbusFrameStr(slaveId, functionCode, registerAddress, registerValue);

    // step2：调用java函数执行命令
    serialCommand.sendSerialData(modbusFrameStr);

    return true;
}
